package com.baofu.paycore.service.processor.refund;

import com.baofu.paycore.common.enums.FundTypeEnum;
import com.baofu.paycore.common.exception.PayCoreServiceException;
import com.baofu.paycore.common.exception.ServiceErrorCode;
import com.baofu.paycore.manager.model.*;
import com.baofu.paycore.service.converter.BO2BOConverter;
import com.baofu.paycore.service.facade.enums.PayToolTypeEnum;
import com.system.commons.sequence.redis.SequenceFacade;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 余额支付退款资金单构建处理器
 * <p>
 *     1、余额支付退款资金单构建
 * </p>
 * User: kwl Date: 2016/11/3 ProjectName: paycore Version: 5.0.0
 */
@Slf4j
@Service
public class RefundAccountProcessor {

    /**
     * 支付单号序列成工具类
     */
    @Autowired
    private SequenceFacade sequenceFacade;


    /**
     * 余额支付退款资金单构建
     *
     * <p>
     * 余额支付退款，是针对只有余额进行支付的交易的退款操作。
     * 目前，余额支付的退款方向，只退款到余额账户，不考虑退款到其他支付工具
     * </p>
     *
     * @param refundBO        支付模型
     * @param subPayBOs       原支付交易资金单
     */
    public void process(RefundBO refundBO, List<SubPayBO> subPayBOs) {

        log.debug("余额支付退款资金单构建参数, refundBO:{}, subPayBOs:{}",refundBO, subPayBOs);

        //余额支付 退款资金单资金集合
        List<SubRefundBO> subBOs = new ArrayList<>();

        //本次退款，退“手续费” 总金额
        Long refundFeeAmt = refundBO.getRefundFeeAmt() - refundBO.getHasRefundFeeAmt();

        //业务退款总金额：本次退款，除去退款收取的“手续费”金额 和  原交易退“手续费”的剩余金额
        Long refundAmt = refundBO.getAmt() - refundBO.getHasRefundAmt() - refundBO.getFeeAmt() - refundFeeAmt;

        //循环迭代原支付资金单，构建对应退款资金单
        for(SubPayBO subPayBO : subPayBOs) {

            //原资金单剩余可退款金额
            Long availableRefundAmt = subPayBO.getAvailableRefundAmt();
            if (0 == availableRefundAmt) {
                continue;
            }

            FundTypeEnum fundTypeEnum = FundTypeEnum.explain(subPayBO.getFundType());
            if(null == fundTypeEnum){
                log.error("原支付单资金明细异常, fundType:{},error:{}",subPayBO.getFundType(),
                        ServiceErrorCode.FUND_TYPE_ERROR);
                throw new PayCoreServiceException(ServiceErrorCode.FUND_TYPE_ERROR);
            }

            //本次资金单 “退款金额”
            Long payToolRefundAmt ;

            switch (fundTypeEnum) {

                case FEE:

                    //若手续费总退款金额为0,直接跳出
                    if (0 == refundFeeAmt) {
                        break;
                    }
                    payToolRefundAmt = (refundFeeAmt - availableRefundAmt > 0) ? availableRefundAmt :
                            refundFeeAmt;
                    refundFeeAmt -= payToolRefundAmt;

                    subPayBO.setRefundTradeAmt(payToolRefundAmt);
                    subPayBO.setRefundAmount(subPayBO.getRefundAmount() + payToolRefundAmt);
                    refundBO.setHasRefundFeeAmt(refundBO.getHasRefundFeeAmt() + payToolRefundAmt);

                    transFerRefundProcess(subPayBO, refundBO, payToolRefundAmt, subBOs);
                    break;

                case PAY:

                    //若总退款金额为0，直接跳出
                    if (0 == refundAmt) {
                        break;
                    }
                    payToolRefundAmt = (refundAmt - availableRefundAmt > 0) ? availableRefundAmt : refundAmt;
                    refundAmt -= payToolRefundAmt;

                    subPayBO.setRefundTradeAmt(payToolRefundAmt);
                    subPayBO.setRefundAmount(subPayBO.getRefundAmount() + payToolRefundAmt);
                    refundBO.setHasRefundAmt(refundBO.getHasRefundAmt() + payToolRefundAmt);

                    //支付资金单退款，
                    transFerRefundProcess(subPayBO, refundBO, payToolRefundAmt, subBOs);
            }
        }

        refundBO.getSubRefundBOMap().put(PayToolTypeEnum.ACCOUNT.getCode(), subBOs);
        refundBO.getSubRefundBOs().addAll(subBOs);
    }

    /**
     * 转账退款流程
     *
     * <p>
     * 将银行卡充值对应的转账资金单的退款单放入退款资金单集合中。并放入到集合的首位，这是考虑银行卡充值的退款，
     * 即，保证现将商户收单资金退还到用户手中，在将用户的资金原路退还到 充值的待清算-应收账户中。
     * </p>
     *
     * @param subPayBO            原支付单
     * @param refundBO            退款主单
     * @param payToolRefundAmt    本次该资金单（支付工具）退款金额
     * @param subRefundBOs        退款资金单集合
     */
    private void transFerRefundProcess(SubPayBO subPayBO, RefundBO refundBO, Long payToolRefundAmt,
                                       List<SubRefundBO> subRefundBOs){

        SubRefundBO subRefundBO = new SubRefundBO();
        subRefundBO.setFundDetailNo(sequenceFacade.getUniqueSeq());
        subRefundBO.setPayToolType(subPayBO.getPayToolType());
        subRefundBO.setAmt(payToolRefundAmt);

        subRefundBOs.add(BO2BOConverter.getSubRefundBOBySubPayBO(subPayBO, refundBO, subRefundBO));
    }

}
